第二十課:useFetch的loading特效應用
前一天我們都順利地使用了useFetch來抓取我們要的資料,提到了在useFetch中useEffect的作用,而今天要來處理如何加入loading時的特效,讓抓取資料的過程中,提升我們的使用者體驗。
這邊將實作如何將我們的首頁UI加入與Api串接時的特效,屬於實物面的功能特效,與一開始做的UI特效都不同,因為有牽扯到Api。
skeleton 為骨架之意,代表說是載入時先顯現到時候資料會出來的樣子,以心理學來說,使用者會覺得好像快出現了,至少已經一半了可以再等等,來將低因網速使顧客跳出網站的流失率,且在功能上也會讓連線更快,因為猜分需要抓資料的部分與UI生成時間,一般的網站都會先抓取好全部再一起顯示畫面,相較於這樣傳統的網站,使用await axios搭配動畫會讓人有這個網站載入更快的錯覺,因抓取龐大資料所需時間最久,了解後這邊我們會將原本的"人氣民宿.."先做改變。
所以首先我們要以usefetch中的loading為主,當他傳入loading值為true,代表在載入中,我們就可以放上skeleton loading特效。所以回到我們的popularHotel的父層feature來應用到我們沒應用到的loading useState。
沒加入skeleton loading的版本
const PopularHotels = ({ dataArray, loading }) => {
//loading 現在從 feature useFetch Api那傳資料回來了
return (
<div className='popularHotels'>
{ loading ? <>我在載入不顯示</> :
//利用loading = true 時 顯示 "冒號" 後面的原本dataArray
//利用loading = false 時 顯示 "問號" 後面的<>我在載入不顯示</>
<>{dataArray.map((item, index) =>
<Link to={`/hotels/${item._id}`} style={{ textDecoration: "none", color: "inherit" }} key={index}>
<div className="item" >
<img src={item.photos[0]} alt="" />
<div className="itemInfo">
<div className="title">
{item.name}
</div>
<div className="subTitle">
{item.city}
</div>
<div className="price">
TWD {item.cheapestPrice.toLocaleString()} 起
</div>
<div className="rate">
<button>{item.rating}</button>
<span>{item.rating >= 9.5 ? "好極了" : "傑出"}</span>
<p>{item.comments.toLocaleString()}則評論</p>
</div>
</div>
</div>
</Link>)}
</>
}
</div>
)
}
並來製作Skeleton Component細節
這邊其實兩種方法都可以看使用者覺得哪個管理上會比較方便,到時後可以一起決定要導入的props與統一導入性,不再增加更多的遮罩components的另一種可讀性,可以選擇這樣輸出
const Skeleton = ({ type,length}) => {
const number = length
//length為傳入資料數目,讓這個遮罩要計算要生成多少個遮障
const PopularHotelSkeleton = ({i}) => (
//多一個{i}是因為解決list需要index的部分,不然會有warning
<div className="popularHotelSK" key={i} >
<div className='imgSK' />
<div className="InfoSK">
<div className="titleSK" />
<div className="subTitleSK" />
<div className="priceSK" />
<div className="rateAndCommentSK" />
</div>
</div>
);
const AmountSkeleton = () => (
<div className="amountSK" />
);
if (type === "popularHotel") return Array(number).fill().map((item,i)=><PopularHotelSkeleton key={i}/>);
//用Array來排列這麼多的遮罩,假設說我們傳入為7,那他就會生成7個遮罩,取代原本的資料列 .map() 來把array列陣同時又加index不然又會有error發生
if (type === "Amount") return (<AmountSkeleton />);
//amount 不用是因為他有上面得data.js的UI內資料不像PopularHotels是整個傳過來的資料總數都不確定
//而Amount是因為是我們的測試做的type與city就都知道有這麼多就不用在傳入length告訴他要生成多少個遮罩
}
export default Skeleton
並這邊下面我們加入type子句,到時候我們要去popularHotels啟動遮罩時,告訴他說我要用的skeleton的type是popularHotel,這邊就會輸出我們的<PopularHotelSkeleton />
並這邊我們會加入想要生成的遮罩數目為lengh
.popularHotelSK {
position: relative;
.imgSK {
width: 250px;
height: 230px; //跟原本img一樣的長寬高
background-color:#ECECEC;
margin-bottom: 2px;
}
.InfoSK {
display: flex;
flex-direction: column;
gap:2px;
.titleSK {
width: 220px;
height: 25px;
background-color:#ECECEC;
}
.subTitleSK {
width: 70px;
height: 15px;
background-color:#ECECEC;
}
.priceSK {
width: 150px;
height: 20px;
background-color:#ECECEC;
}
.rateAndCommentSK {
width: 190px;
height: 25px;
background-color:#ECECEC;
}
}
}
.amountSK {
position: relative;
width: 150px;
height: 30px;
background-color:#ECECEC;
}
並做好後,我們先回到,我們的popularHotel.js component在那導入完整的Sketelon包括import 還有我們上面要判讀的type與length
並完成後應該就會有簡單,但沒有加入動畫的顯影。
了解@keyframes後,我們將利用keyframes與動畫幀數的概念,配合scss加入在我們原本的Sketelon loading上,這邊有很多種動畫玩法,我們就先用最基本且較簡單的控制他的透明度來明暗、明暗的顯示載入畫面。
@keyframes skeleton {
to {
opacity: 0.6;
}
}
animation: skeleton 1s ease infinite alternate;
這邊完成後可以回popularHotels,把我們設的isloading假boolean值刪掉,串接回原來的loading他就能正常在axios.get時,抓取資料等待時間時會顯示。
最後來收尾一下將我們的前面只要有資料傳接的部分,資料需要載入的,都搭配useFetch中useState的loading,結合我們的skeleton loading來做特效,並我們在feature.jsx component使用的useFetch在導入在popularHotels,而我們接下來要加的AmountSkeleton會加在我們的categories.jsx,來遮罩我們的type與city統計的數目,所以要用到categories裡面的useFetch,使用他的loading並一樣導入skeleton並props我們的AmountSkeleton來讓他識別,資料長度length就不用因為我們直接導入在map內,如下。
<div className="desc">
{loading ? <Skeleton type="Amount"/> : `${data[index]}間住宿`}
</div>
最後完成應該會示範影片應該會是下面這樣,全部都在載入的地方都是有關資料庫的連接。
恭喜目前鐵人賽已經完成到2/3,這幾天我們會發現網站的許多細節,現今看似理所當然卻富含很多巧思,甚至涉及到行銷的概念,如何用你的產品來留住消費者,讓他們能使用起來最舒服且安心。我們在剩下的10天內,雖然我們無法把所有細節的完成,但秉持著這樣的細節與現在開發慢慢開始所累積的概念,不管之後去跟別人合作,還是請別人幫你製作都會有概念,對自己都是無往不利的。